/* Copyright (C) 2010  Romolo Camplani, Marco Fortunato, Marco Marelli, Guido Rota, Fabio A. Schreiber et al.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

package org.dei.perla.sys.persistence;

import java.sql.SQLException;
import org.dei.perla.component.Startable;
import org.dei.perla.sys.query.llqruntime.datastructures.Buffer;
import org.dei.perla.sys.query.llqruntime.datastructures.OutOfBoundsBufferException;
import org.dei.perla.utils.waiter.Waiter;

/**
 * La seguente � una sottoclasse della classe DataPersitent e si occuppa di realizzare
 * la persistenza dei dati perseguendo una sorta di politica basata sul numero di record,
 * sfruttando i metodi messi a disposizione della classe padre DataPersistent.
 * Pi� precisamente questo tipo di politica consite nel rendere persistenti i record presenti 
 * nel Buffer, ogni volta che sono presenti pi� di un certo numero di recod nel Buffer. 
 * La politica � realizzata mediante l'utilizzo di una inner class, che sostanzialemente crea 
 * un thread, che aziona il meccanismo di persistenza solo quando si accorge che nel buffer 
 * sono presenti il numero di record voluti. 
 * Il thread � volutamente nascosto a oloro che utilizzano la classe, ma che possono gestire 
 * agevolmente sfruttando i metodi messi a disposizione dall' interfaccia Startable, 
 * opportunamente implementati.
 * @author Luigi Rinaldi & Matteo Rovero
 *
 */
public class DataPersistentRecordPolitic extends DataPersistent implements Startable{ 

	private Waiter<Buffer> pWaiter;
	private Thread persistenceThread;
	private int numberOfRecords;
	
	/**
	 * Richiama il costruttore della superclasse
	 * @param buff oggetto Buffer da cui prelevare i record.
	 * @param nameOfTable  tabella MySql che conterr� i record del buff.
	 * @param numberOfRecords numero di record che devono essere presenti nel Buffer prima che possano 
	 * essere salvati in memoria. Per definizione non pu� essere negativo o nullo.
	 * @throws NotValidNameException eccezione sollevata nel caso in cui il nome della Tabella risulta 
	 * gi� utilizzato nel DB.
	 * @throws NullBufferException eccezione sollevata nel caso in cui il Buffer passato sia null.
	 * @throws OutOfBoundsException eccezione sollevata nel caso in cui il parametro numberOfRecords
	 * sia negativo o nullo.
	 */
	public DataPersistentRecordPolitic(Buffer buff, String nameOfTable, int numberOfRecords) throws NullBufferException, NotValidNameException, OutOfBoundsException{
		super(buff, nameOfTable);
		if(numberOfRecords <= 0) throw new OutOfBoundsException();
		pWaiter = new Waiter<Buffer>();
		pWaiter.addWaitable(buff.getWaitable());
		this.persistenceThread = new Thread(new ThreadImplementation());
		this.numberOfRecords = numberOfRecords;
	}


	@Override
	public boolean isStarted() {
		return this.persistenceThread.isAlive();
	}


	@Override
	public void start() {
		this.persistenceThread.start();
	}


	@Override
	public void stop() {
		if(isStarted()){
			this.persistenceThread.interrupt();
		}
	}
	
	/**
	 * Realizza un thread che si preoccupa di verificare se nel Buffer sono presenti un dato numero di record.
	 * Ogni qual volta la precendente condizione risulta vera, attua una precedura per il salvataggio del 
	 * blocco di record e successivamente li elimina dal Buffer.
	 * @author Luigi Rinaldi & Matteo Rovero
	 *
	 */
	private class ThreadImplementation extends Thread {
		
		private boolean newTable = true; 
		
		public ThreadImplementation() {
			pWaiter.start();
		}
		
		@Override
		/**
		 * Se nel buffer sono presenti numberOfRecords, attua il meccanismo di salvataggio record.
		 */
		public void run(){
			while(!persistenceThread.isInterrupted()){
				if(buff.getWaitable() == pWaiter.waitNext() && buff.getBuffer().size() >= numberOfRecords){	
					if(newTable){
						try {
							System.out.println("creo tabella");
							createTable();
							newTable=false;
						} catch (SQLException e1) {
							e1.printStackTrace();
						} catch (ClassNotFoundException e2) {
							e2.printStackTrace();
						}
					}
					try {
						saveRecords(numberOfRecords);
					} catch (OutOfBoundsBufferException e3) {
						e3.printStackTrace();
					}
				}
			}
		}
	}	

}
